/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.databaseobject.manager;

import io.iec.edp.caf.databaseobject.api.context.DatabaseObjectContext;
import io.iec.edp.caf.databaseobject.api.entity.*;
import io.iec.edp.caf.databaseobject.api.service.IDatabaseObjectService;
import io.iec.edp.caf.databaseobject.common.DatabaseObjectCheckUtil;
import io.iec.edp.caf.databaseobject.common.DatabaseObjectCommonUtil;
import io.iec.edp.caf.databaseobject.manager.persistent.RepositoryFactory;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhaoleitr
 */
public class DatabaseObjectServiceImpl implements IDatabaseObjectService {
    /**
     * 根据全路径获取数据库对象
     *
     * @param fullPath 全路径
     * @return 数据库对象
     */
    @Override
    public AbstractDatabaseObject getDatabaseObject(String fullPath) {
        AbstractDatabaseObject databaseObject = null;
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        try {
            String content = RepositoryFactory.getInstance().getDatabaseObjectManagerRepository().read(fullPath);
            databaseObject = commonUtil.deserialze(content);
            databaseObject = commonUtil.deserialze(databaseObject.getType(),content);
        } catch (Exception e) {
            throw new RuntimeException("根据路径获取数据库对象报错", e);
        }
        return databaseObject;
    }


    @Override
    public List<DatabaseObjectInfo> getDatabaseObjectList(String fullPath) {

        if (!(new File(fullPath)).isDirectory()) {
            RepositoryFactory.getInstance().getDatabaseObjectManagerRepository().createFolder(fullPath);
            return null;
        }
        List<String> filePaths = RepositoryFactory.getInstance().getDatabaseObjectManagerRepository().getFilePathsRecursivly(fullPath);
        List<DatabaseObjectInfo> objectList = getDboInfoList(filePaths);
        return objectList;
    }

    @Override
    public void saveDatabaseObjectTableWithoutFileName(String fullPath, DatabaseObjectTable databaseObject) {
        String result = Paths.get(fullPath, databaseObject.getCode() + DatabaseObjectContext.getSuffix()).toString();
        RepositoryFactory.getInstance().getDatabaseObjectManagerRepository().createDatabaseObject(result, databaseObject);
    }

    private List<DatabaseObjectInfo> getDboInfoList(List<String> filePaths) {
        List<DatabaseObjectInfo> objectList = new ArrayList<>();
        if (filePaths != null && filePaths.size() > 0) {
            for (String filePath : filePaths) {

                DatabaseObjectInfo databaseObject = getDatabaseObjectInfo(filePath);
                if (databaseObject != null) {
                    objectList.add(databaseObject);
                }
            }
        }
        return objectList;
    }

    @Override
    public List<AbstractDatabaseObject> getDatabaseObjectListRecursivly(String fullPath) {
        if (!(new File(fullPath)).isDirectory()) {
            throw new RuntimeException("目录不存在:" + fullPath);
        }
        List<String> filePaths = RepositoryFactory.getInstance().getDatabaseObjectManagerRepository().getFilePathsRecursivly(fullPath);
        List<AbstractDatabaseObject> result = new ArrayList<>();
        if (filePaths != null && filePaths.size() > 0) {
            for (String filePath : filePaths) {

                AbstractDatabaseObject databaseObject = getDatabaseObject(filePath);
                if (databaseObject != null) {
                    result.add(databaseObject);
                }
            }
        }
        return result;
    }

    /**
     * 判断DBO是否存在
     *
     * @param fullPath 全路径
     * @param dboCode  code
     * @param dboId    id
     * @return 是否
     */
    @Override
    public boolean isExistDatabaseObject(String fullPath, String dboCode, String dboId) {
        DatabaseObjectInfo databaseObjectInfo = null;
        if (StringUtils.isBlank(dboCode) && StringUtils.isBlank(dboId)) {
            throw new RuntimeException("调用该方法时，数据库对象编号和ID不能同时为空");
        }
        if (StringUtils.isNotBlank(dboId)) {
            databaseObjectInfo = getDatabaseObjectInfoById(fullPath, dboId);
            if (databaseObjectInfo != null) {
                if (StringUtils.isNotBlank(dboCode)) {
                    return true;
                }
                DatabaseObjectInfo info = getDatabaseObjectInfoByCode(fullPath, dboCode);
                if (info != null && !info.getId().equals(dboId)) {
                    throw new RuntimeException(fullPath + "已经存在编号为" + dboCode + "的数据库对象");
                }
            } else if (StringUtils.isNotBlank(dboCode)) {
                if (getDatabaseObjectInfoByCode(fullPath, dboCode) == null) {
                    return false;
                } else {
                    throw new RuntimeException(fullPath + "已经存在编号为" + dboCode + "的数据库对象");
                }
            }
            return false;
        } else if (StringUtils.isNotBlank(dboCode)) {
            DatabaseObjectInfo info = getDatabaseObjectInfoByCode(fullPath, dboCode);
            return info != null;
        }
        return true;
    }

    @Override
    public DatabaseObjectInfo getDatabaseObjectInfo(String fullPath, String dboCode, String dboId) {
        DatabaseObjectInfo databaseObjectInfo = null;
        if (StringUtils.isBlank(dboCode) && StringUtils.isBlank(dboId)) {
            throw new RuntimeException("调用该方法时，数据库对象编号和ID不能同时为空");
        }
        if (StringUtils.isNotBlank(dboId)) {
            databaseObjectInfo = getDatabaseObjectInfoById(fullPath, dboId);
            if (databaseObjectInfo != null) {
                if (StringUtils.isNotBlank(dboCode)) {
                    return databaseObjectInfo;
                }
                DatabaseObjectInfo info = getDatabaseObjectInfoByCode(fullPath, dboCode);
                if (info != null && !info.getId().equals(dboId)) {
                    throw new RuntimeException(fullPath + "已经存在编号为" + dboCode + "的数据库对象");
                }
            } else if (StringUtils.isNotBlank(dboCode)) {
                if (getDatabaseObjectInfoByCode(fullPath, dboCode) == null) {
                    return null;
                } else {
                    throw new RuntimeException(fullPath + "已经存在编号为" + dboCode + "的数据库对象");
                }
            }
            return null;
        } else if (StringUtils.isNotBlank(dboCode)) {
            DatabaseObjectInfo info = getDatabaseObjectInfoByCode(fullPath, dboCode);
            return info;
        }
        return null;
    }

    @Override
    public AbstractDatabaseObject getDatabaseObjectById(String fullPath, String databaseObjectId) {
        List<AbstractDatabaseObject> databaseObjects = getDatabaseObjectListRecursivly(fullPath);
        List<AbstractDatabaseObject> dbo = databaseObjects.stream().filter((item) -> item.getId().equals(databaseObjectId)).collect(Collectors.toList());
        if (dbo.size() > 1) {
            throw new RuntimeException("存在多个相同ID的数据库对象，数据库对象ID为：" + databaseObjectId);
        }
        if (dbo.size() <= 0) {
            return null;
        }
        return dbo.get(0);
    }

    /**
     * 获取单个dbo详细信息
     *
     * @param path 路径
     * @return 数据库对象信息
     */
    private DatabaseObjectInfo getDatabaseObjectInfo(String path) {
        if (!path.endsWith(DatabaseObjectContext.getSuffix())) {
            return null;
        }
        DatabaseObjectInfo result = null;
        String str = RepositoryFactory.getInstance().getDatabaseObjectManagerRepository().read(path);
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        AbstractDatabaseObject databaseObject = null;
        try {
            databaseObject = commonUtil.deserialze(str);
        } catch (Exception e) {
            String[] splits=path.split("/|\\\\");
            String fileName=splits[splits.length-1];
            throw new RuntimeException("反序列化数据库对象"+fileName+"报错", e);
        }
        if (databaseObject != null) {
            result = new DatabaseObjectInfo();
            result.setId(databaseObject.getId());
            result.setCode(databaseObject.getCode());
            result.setName(databaseObject.getName());
            result.setType(databaseObject.getType());
            result.setFilePath(path);
        }
        return result;
    }

    /**
     * 根据相对路径及ID获取数据库对象基础信息
     *
     * @param fullPath 全路径
     * @param dboId    id
     * @return DatabaseObjectInfo
     */
    public DatabaseObjectInfo getDatabaseObjectInfoById(String fullPath, String dboId) {
        List<DatabaseObjectInfo> infos = getDatabaseObjectList(fullPath);
        if (infos == null) {
            return null;
        }
        List<DatabaseObjectInfo> dbo = infos.stream().filter((item) -> item.getId().equals(dboId)).collect(Collectors.toList());
        if (dbo.size() > 1) {
            throw new RuntimeException("存在多个相同ID的数据库对象，数据库对象ID为：" + dboId);
        }
        if (dbo.size() <= 0) {
            return null;
        } else {
            return dbo.get(0);
        }
    }

    /**
     * 根据相对路径及code获取数据库对象基础信息
     *
     * @param fullPath 全路径
     * @param dboCode  code
     * @return DatabaseObjectInfo
     */
    public DatabaseObjectInfo getDatabaseObjectInfoByCode(String fullPath, String dboCode) {
        List<DatabaseObjectInfo> infos = getDatabaseObjectList(fullPath);
        if (infos == null) {
            return null;
        }
        List<DatabaseObjectInfo> dbo = infos.stream().filter((item) -> item.getCode().equals(dboCode)).collect(Collectors.toList());
        if (dbo.size() > 1) {
            throw new RuntimeException("存在多个相同Code的数据库对象，数据库对象Code为：" + dboCode);
        }
        if (dbo.size() <= 0) {
            return null;
        } else {
            return dbo.get(0);
        }
    }

    @Override
    public DBInfo getDbInfo() {
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        return commonUtil.getCurrentDbInfo();
    }
}
